<?php
/**
 * MonkeyPHP的公共函数都在这里了\
 * @package    \
 * @author     HuangYi
 * @copyright  Copyright (c) 2011-07-01——2013-03-30
 * @license    New BSD License
 * @version    $Id: \Monkey\function.php 版本号 2013-03-30 $
 */

/**
 * 简单打印函数
 * @param mixed $var
 */
function pre($var) {
    echo '<pre>';
    print_r($var);
    echo '</pre>';
}
/**
 * dump
 * 浏览器友好的变量输出
 * 出自ThinkPHP
 * @param mixed $var 要打印的数据
 * @param bool $echo 是否直接输出
 * @param string $label 输出标签
 * @param bool $strict 精确输出
 * @return string|void
 */
function dump($var, $echo=true, $label=null, $strict=true) {
    $label = ($label === null) ? '' : rtrim($label) . ' ';
    if (!$strict) {
        if (ini_get('html_errors')) {
            $output = print_r($var, true);
            $output = "<pre>".$label.htmlspecialchars($output, ENT_QUOTES)."</pre>";
        } else {
            $output = $label . " : " . print_r($var, true);
        }
    } else {
        ob_start();
        var_dump($var);
        $output = ob_get_clean();
        if (!ini_get('xdebug.overload_var_dump')) {
            $output = preg_replace("/\]\=\>\n(\s+)/m", "] => ", $output);
            $output = '<pre>'.$label.htmlspecialchars($output, ENT_QUOTES).'</pre>';
        }
    }
    if ($echo) {
        echo($output);
        return null;
    }else{
        return $output;
    }
}
/**
 * 公用通知包装
 * @param bool $status 状态
 * @param mixed $info 信息
 * @param string $type =array 返回通知包的数据类型： array（默认）、json（对array进行json编码）
 * @return array|string
 */
function notice($status,$info,$type='array'){
    $data=array('status'=>(bool)$status,'info'=>$info);
    return $type==='json'?json_encode($data):$data;
}
/**
 * 获取客户端IP
 * @return string
 */
function ip(){
    static $ip=null;
    if($ip)return $ip;
    if (getenv("HTTP_CLIENT_IP")
        && strcasecmp(getenv("HTTP_CLIENT_IP"), "unknown")
    ){
        $ip = getenv("HTTP_CLIENT_IP");
    }else if (getenv("HTTP_X_FORWARDED_FOR")
        && strcasecmp(getenv("HTTP_X_FORWARDED_FOR"), "unknown")
    ){
        $ip = getenv("HTTP_X_FORWARDED_FOR");
    }else if (getenv("REMOTE_ADDR")
        && strcasecmp(getenv("REMOTE_ADDR"), "unknown")
    ){
        $ip = getenv("REMOTE_ADDR");
    }else if (isset($_SERVER['REMOTE_ADDR'])
        && $_SERVER['REMOTE_ADDR']
        && strcasecmp($_SERVER['REMOTE_ADDR'], "unknown")
    ){
        $ip = $_SERVER['REMOTE_ADDR'];
    }else{
        $ip = "unknown";
    }
    $ip==='::1' and $ip='127.0.0.1';
    return $ip;
}
//如果json_encode没有定义，则定义json_encode函数，常用于返回ajax数据
if (!function_exists('json_encode')){
    /**
     * @param $value
     * @return string
     */
    function format_json_value(&$value) {
        if(is_bool($value))        {
            $value = $value?'true':'false';
        }else if(is_int($value))        {
            $value = intval($value);
        }else if(is_float($value))        {
            $value = floatval($value);
        }else if(defined($value) && $value === null)        {
            $value = strval(constant($value));
        }else if(is_string($value))        {
            $value = '"'.addslashes($value).'"';
        }
        return $value;
    }
    /**
     * @param $data
     * @return string
     */
    function json_encode($data)    {
        if(is_object($data))        {
            $data = get_object_vars($data);//对象转换成数组
        }else if(!is_array($data))        {
            return format_json_value($data); // 普通格式直接输出
        }
        // 判断是否关联数组
        if(empty($data) || is_numeric(implode('',array_keys($data))))        {
            $assoc  =  false;
        }else{
            $assoc  =  true;
        }
        // 组装 Json字符串
        $json = $assoc ? '{' : '[' ;
        foreach($data as $key=>$val)        {
            if(!is_null($val)){
                if($assoc){
                    $json .= "\"$key\":".json_encode($val).",";
                } else {
                    $json .= json_encode($val).",";
                }
            }
        }
        if(strlen($json)>1){ $json  = substr($json,0,-1);}// 加上判断 防止空数组
        $json .= $assoc ? '}' : ']' ;
        return $json;
    }
}
/**
 * 压缩文本内容，发送http页面内容过大的时候应用
 * 也可在配置中直接wy::$ini['system']['gzip_auto']设为TRUE，框架就会自动处理了;
 * 当配置自动
 * @param string $content 内容
 * @return string
 */
function gzip($content) {
    static $level=false;
    $level===false and $level=oApp()->gzipLevelSet;
    if( !headers_sent() &&
        extension_loaded("zlib")
        && !ini_get('zlib.output_compression')
        && strstr($_SERVER['HTTP_ACCEPT_ENCODING'],'gzip')!== FALSE
    ){
        $content = gzencode($content,$level);
        header('Content-Encoding: gzip');
    } else {
        header('Content-Encoding: none');
    }
    header('Content-Length: '.strlen($content));
    return $content;
}
/**
 * 转义变量 用于安全调用，如SQL值
 * @param array|string $data 字符或数组
 * @return array|string
 */
function addslashesOfDeep($data) {
    return is_array($data)?array_map(__FUNCTION__ , $data): addslashes( $data );
}
/**
 * 对变量进行反转义到原始数据
 * @param array|string $data 字符或数组
 * @return array|string
 */
function stripslashesOfDeep($data) {
    return is_array($data)?array_map(__FUNCTION__ , $data): stripslashes( $data );
}

/**
 * 生成令牌
 * @param string $name 令牌名
 * @return string|boolean 令牌值或False
 */
function tokenMake($name){
    !isset($_SESSION[$name]) and $_SESSION[$name]  = md5(microtime(TRUE).'monkey'.$name);
    return $_SESSION[$name];
}
/**
 * 验证令牌
 * @param string $name 令牌名
 * @return bool
 */
function tokenCheck($name) {
    $tokenValue=$_POST[$name]?$_POST[$name]:$_GET[$name];
    return ($tokenValue && $_SESSION[$name]==$tokenValue);
}

/******************目录操作有关函数*******************/
/**
 * 格式化目录变量：1、分隔符统一替换为'/'2、末尾统一去掉'/'
 * @param string $dir 待格式化的字符串
 * @return string
 */
function dirFormat(&$dir){
    DIRECTORY_SEPARATOR!='/' and $dir=str_replace(DIRECTORY_SEPARATOR, '/', $dir);
    substr($dir,-1)=='/' and $dir=substr($dir,0,-1);
    return $dir;
}
/**
 * @static
 * 检查目录的可写入性，不可写入时，尝试变为可写入。
 * @param string $targetDir 目标目录
 * @return boolean
 */
function dirCheckWritable($targetDir){
    //检查缓存目录是否可写，不可写则修改它的属性
    if(!is_dir($targetDir))return false;
    elseif(!is_writable($targetDir) && !@chmod($targetDir,0777))return false;
    return true;
}
/**
 * @static
 * 检查目录是否存在
 * 当目录不存在时创建它
 * @param string $targetDir 目标目录,不支持相对目录
 * @return boolean
 */
function dirCheck(&$targetDir) {
    $targetDir=dirFormat($targetDir);
    if(is_dir($targetDir))return TRUE;
    $temp=$targetDir[0];
    if($temp=='.')return false;
    $tempDir=explode('/', $targetDir);
    $subDir=$tempDir[0];
    array_shift($tempDir);
    foreach ($tempDir as $value) {
        if($value=='') continue;
        if($value=='.' || $value=='..') return false;
        $subDir=$subDir.'/'.$value;
        if (is_dir($subDir)) continue;
        //创建目录
        if(!@mkdir($subDir, 0777) )return false;
    }
    return true;
}
/**
 * @static
 * 递归删除文件夹
 * @param string $targetDir 目标文件夹
 * @return boolean
 */
function dirDelete($targetDir) {
    if (!is_dir($targetDir)) return TRUE; //
    $handle = opendir($targetDir);
    if ($handle) {
        while (($item = readdir($handle)) !== false) {
            if ($item == '.' || $item == '..') continue;
            $itemFile = $targetDir . '/' . $item;
            if (is_dir($itemFile)) {
                dirDelete($itemFile);
                rmdir($itemFile);
            } else {
                unlink($itemFile);
            }
        }
        closedir($handle);
        rmdir($targetDir);
    }
    return TRUE;
}
/**
 * @static
 * 将一个文件夹内容，复制或移动到另一个文件夹
 * @param string $source 源文件夹名
 * @param string $target 目标文件夹
 * @param boolean $delete_source 是否删除源文件夹（是则相当于移动，否则相当于复制）
 * @return boolean
 */
function dirCopy($source, $target,$delete_source=FALSE) {
    $source=dirFormat($source);
    $target=dirFormat($target);
    if($source==$target) return TRUE;
    if(!is_dir($source)) return false;
    dirCheck($target);
    $handle = opendir($source);
    if(!$handle)return false;
    $source_path=$target_path='';
    while (($item = readdir($handle)) !== false) {
        if ($item == '.' || $item == '..') continue;
        $source_path=$source . '/' . $item;
        $target_path=$target.'/'.$item;
        if (is_dir($source_path)) {
            dirCopy($source_path, $target_path, $delete_source);
            if($delete_source ) rmdir($source_path);
        } else{
            copy($source_path, $target_path);
            if($delete_source ) unlink($source_path);
        }
    }
    closedir($handle);
    return true;
}

/****************文件操作函数****************/
/**
 * 通用文件加载函数
 * @param string $file 文件全路径
 * @return bool
 */
function import($file){
    static $loaded=array();
    $file=str_replace('/', DIRECTORY_SEPARATOR,$file);
    if(isset($loaded[$file]))return true;
    if(!file_exists($file))return false;
    require_once($file);
    return $loaded[$file]=true;
}
/**
 * save_variable_to_file
 * 将一个变量写入一个文件中，用$var=include($file)就可以获取保存的变量了
 * @param string $file 文件名
 * @param string|array $variable 变量内容
 */
function fileSaveVariable($file, $variable){
    $variable='<?php'.PHP_EOL.'return '.var_export($variable, TRUE).' ;';
    file_put_contents($file,$variable,LOCK_EX); //echo '<br/>保存扫描结果到缓存文件中...<br/>';
}

/**
 * 将变量写入一个序列化文件中
 * @param string $file 文件名
 * @param string|array $variable 变量内容
 */
function fileSaveSerialize($file,$variable){
    file_put_contents($file,serialize($variable),LOCK_EX); //echo '<br/>保存扫描结果到缓存文件中...<br/>';
}
/**
 * 从一个序列化文件中读取并还原变量
 * @param string $file 文件名
 * @return mixed
 */
function fileReadSerialize($file){
    return unserialize(file_get_contents($file));
}
/**
 * @static
 * 将文件名的扩展名去掉，支持中文名
 * @param string $filename 文件名的部分或完整名称（不含路径）
 * @return string
 */
function fileBasename($filename){
    $pathinfo = pathinfo($filename);
    //return $pathinfo['filename']; //理论上这行也可以，但没验证过。
    $extLen = 1+strlen($pathinfo['extension']);
    return  substr($pathinfo['basename'], 0, 0-$extLen);
}
/**
 * @static
 * 字节数转换成MB格式等
 * @param int $bit  数值
 * @return string
 */
function bitToSize($bit) {
    if(!preg_match('/^[0-9]+$/', $bit)) return 0;
    $type = array( 'B', 'KB', 'MB', 'GB', 'TB', 'PB' );
    $j = 0;
    while($bit >= 1024) {
        if( $j >= 5 ) return $bit.$type[$j];
        $bit = $bit / 1024;
        $j++;
    }
    return $bit.$type[$j];
}
/**
 * @static
 * MB等字符大小格式转换成字节数
 * @param string $size
 * @return int
 */
function sizeToBit($size){
    $size = strtoupper($size);
    if(!preg_match('/^([1-9]\d+\.?\d*)(B|KB|MB|GB|TB|PB)?$/', $size, $matches)) return 0;
    $type = array( 'B'=>0, 'KB'=>1, 'MB'=>2, 'GB'=>3, 'TB'=>4, 'PB'=>5 );
    $bit =intval($matches[1]);
    if($matches[0]==$matches[1]){
        $i=0;
    }  else {
        $i=$type[$matches[2]];
    }
    $j=0;
    while($j<$i){
        $bit=$bit*1024;
        $j++;
    }
    return $bit;
}
/**
 * @static
 * 生成客户端可访问的路径（前端绝对路径）
 * @param string $real_path 实际路径
 * @return string
 */
function fileToUrl($real_path){
    $url=substr($real_path, strlen($_SERVER['DOCUMENT_ROOT']));
    return $url[0]=='/'?$url:'/'.$url;
}
/**
 * ddos拦截防御
 */
function interceptDDOS(){
    static $isrun;
    if($isrun)return;
    $isrun=true;
//查询禁止IP
    $ip =$_SERVER['REMOTE_ADDR'];
    $fileht=".htaccess2";
    if(!file_exists($fileht))file_put_contents($fileht,"");
    $filehtarr=@file($fileht);
    if(in_array($ip."\r\n",$filehtarr))exit("Warning:"."<br>"."Your IP address are forbided by some reason, IF you have any question Pls emill to shop@mydalle.com!");
//加入禁止IP
    $time=time();
    $fileforbid="log/forbidchk.dat";
    if(file_exists($fileforbid))
    { if($time-filemtime($fileforbid)>60)unlink($fileforbid);
    else{
        $fileforbidarr=@file($fileforbid);
        if($ip==substr($fileforbidarr[0],0,strlen($ip)))
        {
            if($time-substr($fileforbidarr[1],0,strlen($time))>600)unlink($fileforbid);
            elseif($fileforbidarr[2]>600){file_put_contents($fileht,$ip."\r\n",FILE_APPEND);unlink($fileforbid);}
            else{$fileforbidarr[2]++;file_put_contents($fileforbid,$fileforbidarr);}
        }
        unset($fileforbidarr);
    }
    }
//防刷新
    $str="";
    $file="log/ipdate.dat";
    if(!file_exists("log")&&!is_dir("log"))mkdir("log",0777);
    if(!file_exists($file))file_put_contents($file,"");
    $allowTime = 120;//防刷新时间
    $allowNum=10;//防刷新次数
    $uri=$_SERVER['REQUEST_URI'];
    $checkip=md5($ip);
    $checkuri=md5($uri);
    $yesno=true;
    $ipdate=@file($file);
    foreach($ipdate as $k=>$v)
    { $iptem=substr($v,0,32);
        $uritem=substr($v,32,32);
        $timetem=substr($v,64,10);
        $numtem=substr($v,74);
        if($time-$timetem<$allowTime){
            if($iptem!=$checkip)$str.=$v;
            else{
                $yesno=false;
                if($uritem!=$checkuri)$str.=$iptem.$checkuri.$time."1\r\n";
                elseif($numtem<$allowNum)$str.=$iptem.$uritem.$timetem.($numtem+1)."\r\n";
                else
                {
                    if(!file_exists($fileforbid)){$addforbidarr=array($ip."\r\n",time()."\r\n",1);file_put_contents($fileforbid,$addforbidarr);}
                    file_put_contents("log/forbided_ip.log",$ip."--".date("Y-m-d H:i:s",time())."--".$uri."\r\n",FILE_APPEND);
                    $timepass=$timetem+$allowTime-$time;
                    exit("Warning:"."<br>"."Sorry,you are forbided by refreshing frequently too much, Pls wait for ".$timepass." seconds to continue!");
                }
            }
        }
    }
    if($yesno) $str.=$checkip.$checkuri.$time."1\r\n";
    file_put_contents($file,$str);
}